package com.soyea.aspect;

import com.google.gson.Gson;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * web层日志切面
 * Created by skh on 2017/12/22
 */
@Component
@Aspect
public class LogAspect {
	private static final Logger LOG = LoggerFactory.getLogger(LogAspect.class);

	private String requestPath = null; // 请求地址
	private Map<?, ?> inputParamMap = null; // 传入参数
	private Map<String, Object> outputParamMap = null; // 存放输出结果
	private long startTimeMillis = 0; // 开始时间
	private long endTimeMillis = 0; // 结束时间
	private String method = null; //请求方式
	private String methodName = null; //请求方法名称
	private String remoteAddr = null; //请求Ip

	@Pointcut("execution(* com.soyea.controller..*.*(..))")
	public void log() {

	}

	/**
	 * @param joinPoint
	 * @Description: 方法调用前触发
	 * 记录开始时间
	 */
	@Before("log()")
	public void doBeforeInServiceLayer(JoinPoint joinPoint) {
		startTimeMillis = System.currentTimeMillis(); // 记录方法开始执行的时间
	}

	/**
	 * @param joinPoint
	 * @Description: 方法调用后触发
	 * 记录结束时间
	 */
	@After("log()")
	public void doAfterInServiceLayer(JoinPoint joinPoint) {
		endTimeMillis = System.currentTimeMillis(); // 记录方法执行完成的时间
		this.printOptLog();
	}

	/**
	 * @return
	 * @throws Throwable
	 * @Description: 环绕触发
	 */
	@Around("log()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		//获取request信息
		RequestAttributes ra = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes sra = (ServletRequestAttributes) ra;
		HttpServletRequest request = sra.getRequest();

		// 获取输入参数
		inputParamMap = request.getParameterMap();

		// 获取请求地址
//		requestPath = request.getRequestURI();
		requestPath = request.getRequestURL().toString();

		// 获取请求方式
		method = request.getMethod();

		// 获取请求方法
		methodName = pjp.getSignature().getName();

		// 获取ip
		remoteAddr = request.getRemoteAddr();

		// 执行完方法的返回值：调用proceed()方法，就会触发切入点方法执行
		outputParamMap = new HashMap<>();
		Object result = pjp.proceed();// result的值就是被拦截方法的返回值
		outputParamMap.put("result", result);

		return result;
	}

	/**
	 * 输出日志
	 */
	private void printOptLog() {
		Gson gson = new Gson();
		String optTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTimeMillis);
		LOG.info("");
		LOG.info("请求地址:{}", requestPath);
//		LOG.info("请求Ip:{}", remoteAddr);
		LOG.info("请求方式:{}", method);
//		LOG.info("请求方法名称:{}", methodName);
		LOG.info("开始时间: {}, 耗时:{}ms", optTime, (endTimeMillis - startTimeMillis));
		LOG.info("请求参数: {}", gson.toJson(inputParamMap));
		LOG.info("返回结果: {}", gson.toJson(outputParamMap));
	}
}

